const fs = require('fs')
const path = require('path')
const { getAst, getDependencies, getCode } = require('./parser.js')

class Compiler {
  constructor(config) {
    const { entry, output } = config
    this.entry = entry
    this.output = output

    this.modules = []
  }

  build(filename) {
    const ast = getAst(filename) // 获取ast
    const dependencies = getDependencies(ast, filename) // 解析出模块的依赖
    const code = getCode(ast) // 使用babel编译成浏览器可以使用的代码

    return {
      filename,
      dependencies,
      code
    }
  }

  file(code) {
    const filePath = path.join(this.output.path, this.output.filename)
    const nweCode = JSON.stringify(code)
    const bundle = `
      (function(graph) {
        function require(module) {
          function localRequire(relativePath) {
            return require(graph[module].dependencies[relativePath])
          }
          var exports = {};
          (function(require, exports, code) {
            eval(code)
          })(localRequire, exports, graph[module].code)
          return exports
        }
        require('${this.entry}')
      })(${nweCode})
    `

    fs.writeFileSync(filePath,  bundle, 'utf-8')
  }

  run() {
    // 从入口文件开始分析模块的依赖以及用babel把文件内容编译成浏览器可用的代码
    const info = this.build(this.entry)

    this.modules.push(info)

    //分析所有import的依赖
    for (let i = 0; i < this.modules.length; i++) {
      const item = this.modules[i]
      const { dependencies } = item
      if (dependencies) {
        for (let key in dependencies) {
          const mInfo = this.build(dependencies[key])
          this.modules.push(mInfo)
        }
      }
    }

    let graph = {}
    this.modules.forEach((item) => {
      const { filename, dependencies, code } = item
      graph[filename] = {
        dependencies,
        code
      }
    })
    console.log(graph)
    this.file(graph)
  }
}

module.exports = Compiler